﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace linkouqs.Gamekit
{
    public enum RaycastDirection
    {
        Up,
        Down,
        Left,
        Right
    }

    public static class BoxCollider2DExtensions
    {
        public static Vector2 FlipX(this BoxCollider2D box)
        {
            var old = box.bounds.center;
            box.transform.localScale = new Vector3(box.transform.localScale.x * -1, 1, 1);
            var delta = box.bounds.center - old;
            return box.transform.position - new Vector3(delta.x, 0);
        }

        static Vector2 GetDirection(BoxCollider2D box, RaycastDirection dir)
        {
            switch (dir)
            {
                case RaycastDirection.Up:
                    return box.transform.up;
                case RaycastDirection.Down:
                    return -box.transform.up;
                case RaycastDirection.Left:
                    return -box.transform.right;
                case RaycastDirection.Right:
                    return box.transform.right;
            }
            return Vector2.zero;
        }

        static float GetRaycastDistance(BoxCollider2D box, RaycastDirection dir, float dist = 0.1f)
        {
            switch (dir)
            {
                case RaycastDirection.Up:
                case RaycastDirection.Down:
                    {
                        return box.size.y * 0.5f + dist;
                    }
                case RaycastDirection.Left:
                case RaycastDirection.Right:
                    {

                        return box.size.x * 0.5f + dist;
                    }
            }
            return dist;
        }

        static List<Vector2> GetRaycastOrigins(BoxCollider2D box, RaycastDirection dir, int count = 3)
        {

            if (count < 3)
            {
                count = 3;
            }

            List<Vector2> results = new List<Vector2>();

            Vector2 center = box.bounds.center;
            Vector2 size = box.size;
            float width = size.x;
            float height = size.y;
            float halfWidth = width * 0.5f;
            float halfHeight = height * 0.5f;
            Vector2 position = center;
            int index = 0;
            switch (dir)
            {
                case RaycastDirection.Up:
                case RaycastDirection.Down:
                    {
                        Vector2 xOffset = box.transform.right * (width / (count - 1));
                        Vector2 offset = -box.transform.right * halfWidth;
                        position += offset;
                        while (index < count)
                        {
                            results.Add(position + xOffset * index);
                            index++;
                        }
                    }
                    break;
                case RaycastDirection.Left:
                case RaycastDirection.Right:
                    {
                        Vector2 yOffset = box.transform.up * (height / (count - 1));
                        Vector2 offset = -box.transform.up * halfHeight;
                        position += offset;
                        while (index < count)
                        {
                            results.Add(position + yOffset * index);
                            index++;
                        }
                    }
                    break;
            }

            return results;
        }

        public static List<Collider2D> RaycastAll(this BoxCollider2D box, RaycastDirection dir, LayerMask layers, float dist = 0.1f, int count = 3)
        {

            List<Collider2D> results = new List<Collider2D>();

            List<Vector2> origins = GetRaycastOrigins(box, dir, count);
            float distance = GetRaycastDistance(box, dir, dist);
            Vector2 direction = GetDirection(box, dir);

            foreach (var origin in origins)
            {
                var hits = Physics2D.RaycastAll(origin, direction, distance, layers.value);
                foreach (var hit in hits)
                {
                    if (hit.collider == null)
                    {
                        continue;
                    }
                    if (results.Contains(hit.collider))
                    {
                        continue;
                    }
                    results.Add(hit.collider);
                }
            }

            return results;
        }

#if UNITY_EDITOR

        public static void DrawRaycast(this BoxCollider2D box, float dist = 0.1f, int count = 3)
        {
            var color = Gizmos.color;
            Gizmos.color = Color.red;

            System.Action<RaycastDirection> draw = (dir) =>
            {
                var _dist = GetRaycastDistance(box, dir, dist);
                var origins = GetRaycastOrigins(box, dir, count);
                foreach (var origin in origins)
                {
                    Gizmos.DrawLine(origin, origin + GetDirection(box, dir) * _dist);
                }
            };

            draw(RaycastDirection.Up);
            draw(RaycastDirection.Down);
            draw(RaycastDirection.Left);
            draw(RaycastDirection.Right);

            Gizmos.color = color;
        }
#endif
    }
}